package tools

import (
	"container/list"
	"fmt"
	"io"
	"reflect"
	"strings"
	"sync"
	"unsafe"
)

type List struct {
	List  list.List
	Rw    sync.RWMutex
	elMap map[string]*list.Element
}

func (l *List) Init() {
	l.List.Init()
	l.elMap = make(map[string]*list.Element)
}

func (l *List) Add(data fmt.Stringer) {
	l.Rw.Lock()
	defer l.Rw.Unlock()
	old := l.elMap[data.String()]
	if old != nil {
		if old.Value == data {
			return
		}
		Log.Println("duplicate service", data.String())
		l.List.Remove(old)
	}
	l.elMap[data.String()] = l.List.PushBack(data)
}

func (l *List) Remove(data fmt.Stringer) (r interface{}) {
	l.Rw.Lock()
	old := l.elMap[data.String()]
	if old != nil {
		r = l.List.Remove(old)
		delete(l.elMap, data.String())
	}
	l.Rw.Unlock()
	return
}

func (l *List) GetByString(s string) (v interface{}) {
	l.Rw.RLock()
	d := l.elMap[s]
	if d != nil {
		v = d.Value
	}
	l.Rw.RUnlock()
	return
}

func CopyAndWait(conn, conn1 io.ReadWriteCloser) {
	done := make(chan struct{})
	go func() {
		defer conn1.Close()
		_, _ = io.Copy(conn1, conn)
		close(done)
	}()
	_, _ = io.Copy(conn, conn1)
	_ = conn.Close()
	<-done
}

func BytesToStringFast(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

func StringToBytes(s string) []byte {
	sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
	bh := reflect.SliceHeader{Data: sh.Data, Len: sh.Len, Cap: sh.Len}
	return *(*[]byte)(unsafe.Pointer(&bh))
}

func SingleJoiningSlash(a, b string) string {
	aslash := strings.HasSuffix(a, "/")
	bslash := strings.HasPrefix(b, "/")
	switch {
	case aslash && bslash:
		return a + b[1:]
	case !aslash && !bslash:
		return a + "/" + b
	}
	return a + b
}

func Min(a, b int) int {
	if a < b {
		return a
	} else {
		return b
	}
}
